/******************************************************************************\
    ContestContestantDataBase.h discribes a database of ties of contests 
	 and contestants.
    It's used with acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#pragma once 

#include ".\BaseDataBase.hpp"

namespace nsContestContestantDataBase
{
	static const long VISIBILITY_LEVEL_BLIND = -1;
	static const long VISIBILITY_LEVEL_ONSITE = 0;
	static const long VISIBILITY_LEVEL_VIRTUAL = 1;
	static const long VISIBILITY_LEVEL_ADMIN = 2;
	static const long	VISIBILITY_LEVEL_GOD = 3;

	struct sContestContestantData0
	{
		unsigned long Key;
		unsigned long ContestId;
		unsigned long ContestantId;
		unsigned long long StartTime;
		long VisibilityLevel;
		unsigned long AdditionTime;
	};

	struct sContestContestantData1
	{
		unsigned long Key;
		unsigned long ContestId;
		unsigned long ContestantId;
		unsigned long long StartTime;
		long VisibilityLevel;
		unsigned long AdditionTime;
	};

	typedef sContestContestantData1 sContestContestantData;

	void ConversionFunction0( void *new_data, const void *prev_data );

	const sConversionTable ConversionTable[] =
	{
		{ sizeof( sContestContestantData0 ), sizeof( sContestContestantData1 ), &ConversionFunction0 }
	};

	struct ContestIdCompare : public std::binary_function< cDataPointer< sContestContestantData >, cDataPointer< sContestContestantData >, bool >
	{
		bool operator()( const cDataPointer< sContestContestantData > &left, const cDataPointer< sContestContestantData > &right ) const
		{
			return left->ContestId < right->ContestId ||
				left->ContestId == right->ContestId && left->ContestantId < right->ContestantId;
		}
	};

	struct ContestantIdCompare : public std::binary_function< cDataPointer< sContestContestantData >, cDataPointer< sContestContestantData >, bool >
	{
		bool operator()( const cDataPointer< sContestContestantData > &left, const cDataPointer< sContestContestantData > &right ) const 
		{
			return left->ContestantId < right->ContestantId ||
				left->ContestantId == right->ContestantId && left->ContestId < right->ContestId;
		}
	};

	typedef cBaseDataBase< sContestContestantData >::KeyIterator KeyIterator;
	typedef cPublicIterator< sContestContestantData, ContestIdCompare > ContestIdIterator;
	typedef cPublicIterator< sContestContestantData, ContestantIdCompare > ContestantIdIterator;

	class cWardContestContestantDataBase : public cBaseDataBase< sContestContestantData >
	{
	private:
		std::set< cDataPointer< sContestContestantData >, ContestIdCompare > ContestIdIndex;
		std::set< cDataPointer< sContestContestantData >, ContestantIdCompare > ContestantIdIndex;
	protected:
		virtual bool Indexed( const cDataPointer< sContestContestantData > &data_pointer )
		{
			return ContestIdIndex.find( data_pointer ) != ContestIdIndex.end() ||
				ContestantIdIndex.find( data_pointer ) != ContestantIdIndex.end();
		}
		virtual void InsertIndex( const cDataPointer< sContestContestantData > &data_pointer )
		{
			ContestIdIndex.insert( data_pointer );
			ContestantIdIndex.insert( data_pointer );
		}
		virtual void UpdateIndex( const cDataPointer< sContestContestantData > &data_pointer, unsigned long index )
		{
			ContestIdIndex.find( data_pointer )->Index = index;
			ContestantIdIndex.find( data_pointer )->Index = index;
		}
		virtual void DeleteIndex( const cDataPointer< sContestContestantData > &data_pointer )
		{
			ContestIdIndex.erase( data_pointer );
			ContestantIdIndex.erase( data_pointer );
		}
		virtual void ClearIndex()
		{
			ContestIdIndex.clear();
			ContestantIdIndex.clear();
		}
	public:
		cWardContestContestantDataBase( /*bool auto_update*/ )
			: cBaseDataBase( /*auto_update*/ )
		{
		}
		ContestIdIterator BeginByContestId() const
		{
			return ContestIdIterator( ContestIdIndex.begin() );
		}
		ContestIdIterator LowerBoundByContestId( unsigned long contest_id ) const
		{
			sContestContestantData contest_contestant_data;
			contest_contestant_data.ContestId = contest_id;
			contest_contestant_data.ContestantId = 0;
			return ContestIdIterator( ContestIdIndex.lower_bound( cDataPointer< sContestContestantData >( &contest_contestant_data ) ) );
		}
		ContestIdIterator UpperBoundByContestId( unsigned long contest_id ) const
		{
			sContestContestantData contest_contestant_data;
			contest_contestant_data.ContestId = contest_id;
			contest_contestant_data.ContestantId = 0xfffffffful;
			return ContestIdIterator( ContestIdIndex.upper_bound( cDataPointer< sContestContestantData >( &contest_contestant_data ) ) );
		}
		ContestIdIterator EndByContestId() const
		{
			return ContestIdIterator( ContestIdIndex.end() );
		}
		ContestantIdIterator BeginByContestandId() const
		{
			return ContestantIdIterator( ContestantIdIndex.begin() );
		}
		ContestantIdIterator LowerBoundByContestantId( unsigned long contestant_id ) const
		{
			sContestContestantData contest_contestant_data;
			contest_contestant_data.ContestantId = contestant_id;
			contest_contestant_data.ContestId = 0;
			return ContestantIdIterator( ContestantIdIndex.lower_bound( cDataPointer< sContestContestantData >( &contest_contestant_data ) ) );
		}
		ContestantIdIterator UpperBoundByContestantId( unsigned long contestant_id ) const
		{
			sContestContestantData contest_contestant_data;
			contest_contestant_data.ContestantId = contestant_id;
			contest_contestant_data.ContestId = 0xfffffffful;
			return ContestantIdIterator( ContestantIdIndex.upper_bound( cDataPointer< sContestContestantData >( &contest_contestant_data ) ) );
		}
		ContestantIdIterator EndByContestantId() const
		{
			return ContestantIdIterator( ContestantIdIndex.end() );
		}
		ContestantIdIterator FindByContestContestant( unsigned long contest_id, unsigned long contestant_id )
		{
			sContestContestantData contest_contestant_data;
			contest_contestant_data.ContestId = contest_id;
			contest_contestant_data.ContestantId = contestant_id;
			return ContestantIdIterator( ContestantIdIndex.find( cDataPointer< sContestContestantData >( &contest_contestant_data ) ) );
		}
		bool GetByContestContestant( unsigned long contest_id, unsigned long contestant_id, sContestContestantData &contest_contestant_data )
		{
			cLocker locker( *this );
			ContestantIdIterator iterator = FindByContestContestant( contest_id, contestant_id );
			if( iterator == ContestantIdIndex.end() )
				return false;
			contest_contestant_data = *iterator;
			return true;
		}
	};

	class cContestContestantDataBase : public cPointerObject< cWardContestContestantDataBase >
	{
	public:
		bool Create( /*bool auto_update = false*/ )
		{
			cWardContestContestantDataBase *ward_contest_contestant_data_base;
			try
			{
				ward_contest_contestant_data_base = new cWardContestContestantDataBase( /*auto_update*/ );
			}
			catch( ... )
			{
				return false;
			}
			if( !SwitchToWardObject( ward_contest_contestant_data_base ) )
			{
				delete ward_contest_contestant_data_base;
				return false;
			}
			return true;
		}
		void Destroy()
		{
			SwitchToSubObject( NULL );
		}
	};
}
